#include "rtc.h"
#include <time.h>

volatile uint32_t nowTime;

uint16_t MyRTC_Time[] = {2023, 8, 29, 21, 33, 00};

void rtc_Init(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);     // 使能 PWR 外设
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);     // 使能 BKP 外设

    PWR_BackupAccessCmd(ENABLE);                            // 使能后备寄存器访问

    if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5) {        // 从指定的后备寄存器中读出数据：读出了与写入的指定数据不相符
        BKP_DeInit();                                       // 复位备份区域
        RCC_LSEConfig(RCC_LSE_ON);                          // 设置外部低速晶振（LSE），使用外设低速晶振
        while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);  // 检查指定的RCC标志位设置与否， 等待低速晶振就绪

        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);             // 设置RTC时钟（RTCCLK), 选择LSE作为时钟
        RCC_RTCCLKCmd(ENABLE);                              // 使能RTC时钟

        RTC_WaitForLastTask();          // 等待最后一次对RTC寄存器的写操作完成
        RTC_WaitForSynchro();           // 等待RTC寄存器同步

        RTC_ITConfig(RTC_IT_SEC, ENABLE);   // 使能RTC秒中断

        RTC_WaitForLastTask();          // 等待最后一次对RTC寄存器的写操作完成

        RTC_EnterConfigMode();          // 允许配置

        RTC_SetPrescaler(32768 - 1);    // 设置RTC预分频的值
        RTC_WaitForLastTask();          // 等待最后一次对RTC寄存器的写操作完成

        rtc_SetTime();                  // 设置时间

        RTC_ExitConfigMode();           // 退出配置模式

        BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
    } else {
        RTC_WaitForSynchro();
        RTC_ITConfig(RTC_IT_SEC, ENABLE);
        RTC_WaitForLastTask();
        
        NVIC_InitTypeDef NVIC_InitStructure;                        // NVIC 中断分组设置
        NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;              // RTC 全局中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;   // 先占优先级1位，从优先级3位
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;          // 先占优先级0位，从优先级4位
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             // 使能改通道中断

        NVIC_Init(&NVIC_InitStructure);                             // 根据NVIC_InitStructure 中指定的参数初始化NVIC寄存器
    }
}

void rtc_SetTime(void)
{
    time_t time_cnt;
    struct tm time_date;
    time_date.tm_year = MyRTC_Time[0] - 1900;
    time_date.tm_mon  = MyRTC_Time[1] - 1;
    time_date.tm_mday = MyRTC_Time[2];
    time_date.tm_hour = MyRTC_Time[3];
    time_date.tm_min  = MyRTC_Time[4];
    time_date.tm_sec  = MyRTC_Time[5];

    time_cnt = mktime(&time_date) - 8 * 60 * 60;

    RTC_SetCounter(time_cnt);
    RTC_WaitForLastTask();
}

void rtc_ReadTime(void)
{
    time_t time_cnt;
    struct tm time_date;

    time_cnt = RTC_GetCounter() + 8 * 60 * 60;

    time_date = *localtime(&time_cnt);

    MyRTC_Time[0] = time_date.tm_year + 1900;
    MyRTC_Time[1] = time_date.tm_mon + 1;
    MyRTC_Time[2] = time_date.tm_mday;
    MyRTC_Time[3] = time_date.tm_hour;
    MyRTC_Time[4] = time_date.tm_min;
    MyRTC_Time[5] = time_date.tm_sec;
}

void RTC_IRQHandler(void)
{
    if (RTC_GetITStatus(RTC_IT_SEC) != RESET)   // 秒钟中断
    {
        rtc_ReadTime();
        nowTime++;
    }
    if (RTC_GetITStatus(RTC_IT_ALR) != RESET)   // 闹钟中断
    {
        RTC_ClearITPendingBit(RTC_IT_ALR);      // 清理闹钟中断
        rtc_ReadTime();
    }
    RTC_ClearITPendingBit(RTC_IT_SEC | RTC_IT_ALR); // 清理闹钟中断和 秒钟中断
    RTC_WaitForLastTask();
}